MODULE P2DBSIM;

FROM InOut 	IMPORT WriteLn, WriteString, Read, Write, WriteCard;
FROM CnjTupla 	IMPORT ObtenerTuplasCnjTupla;
FROM LstTupla 	IMPORT ObtenerLargoLstTupla;
FROM BDatos 	IMPORT DestruirBDatos, EliminarTablaBDatos, BDatos, ObtenerCantTablasBDatos, PerteneceTablaBDatos, ObtenerTablaBDatos, InsertarTablaBDatos, DesplegarBDatos;
FROM Valor 	IMPORT Valor, String, CrearStringValor, CrearEmptyValor, CopiarValor, ObtenerStringValor, DestruirValor,DesplegarValor,MenorValor;
FROM Comando	IMPORT Comando, NombreComando, Parametro, LeerComando, ObtenerNombreComando, ObtenerCantParamComando, ObtenerParamComando;
FROM Columna 	IMPORT ObtenerNombreColumna, DesplegarColumna, NombreColumna, Calificador, Columna, CrearColumna;
FROM LstNom 	IMPORT DestruirLstNom, Nombre, LstNom, CrearLstNom, InsertarNombreLstNom, ObtenerPrimerNombreLstNom,ObtenerRestoLstNom;
FROM Esquema	IMPORT ObtenerRestoEsquema, ObtenerPrimerColumnaEsquema, DesplegarEsquema, EsVacioEsquema, Esquema, InsertarColumnaEsquema, CrearEsquema, ObtenerCantColEsquema;
FROM Strings 	IMPORT Equal, Assign, FindNext, Extract;
FROM Tabla 	IMPORT NombreTabla, Tabla, CrearTabla, ObtenerCnjTuplaTabla, ObtenerEsquemaTabla;
FROM OperTbl 	IMPORT addCol, dropCol, insertInto, delete, update;
FROM Error 	IMPORT Error, Codigo, CrearError, ObtenerCodigoError, DestruirError, PrintError, AsignarCodigoError,AsignarStringError;
FROM LstVal	IMPORT LstVal, InsertarValorLstVal, CrearLstVal;
FROM Cond 	IMPORT Cond, Operador,CrearVaciaCond, CrearCond;

VAR
	BD : BDatos;
	v1 : Valor;
	v2 : Valor;
	v3 : Valor;
	texto : String;
	cmd : Comando;
	cmdName : NombreComando;
	col: Columna;
	nom: NombreColumna;
	cal: Calificador;
	Lst : LstNom;
	LstAux : LstNom;
	Nom : Nombre;
	esq : Esquema;
	err : Error;
(***********************************************)
(*************PROCEDURES AUXILIARES*************)
(***********************************************)
PROCEDURE ExisteCol(nomCol : NombreColumna; tabla : Tabla) : BOOLEAN;
VAR
	esqAux : Esquema;
	colAux : Columna;
	existeCol : BOOLEAN;
BEGIN
	existeCol := FALSE;
	esqAux := ObtenerEsquemaTabla(tabla);
	WHILE (NOT EsVacioEsquema(esqAux)) DO
		colAux := ObtenerPrimerColumnaEsquema(esqAux);
		IF (Equal(ObtenerNombreColumna(colAux), nomCol)) THEN
			existeCol := TRUE;
		END;
		esqAux := ObtenerRestoEsquema(esqAux);					
	END;
	RETURN existeCol;
END ExisteCol;
(***********************************************)
PROCEDURE ImprimirEsquema(cmd : Comando);
VAR
	nameTabla : NombreTabla;
	tabla : Tabla;
BEGIN
	Assign(ObtenerParamComando(1,cmd),nameTabla);
	IF (NOT PerteneceTablaBDatos(nameTabla, BD)) THEN
		AsignarCodigoError(NOEXISTETABLA,err);
		AsignarStringError(nameTabla,err);
		PrintError(err);
	ELSE
		tabla := ObtenerTablaBDatos(nameTabla, BD);
		DesplegarEsquema(ObtenerEsquemaTabla(tabla));			
	END; 	
END ImprimirEsquema;
(***********************************************)
PROCEDURE ImprimirTablas(cmd : Comando);
BEGIN
	DesplegarBDatos(BD);
END ImprimirTablas;
(***********************************************)
PROCEDURE Insertar(cmd : Comando);
VAR
	tabla : Tabla;
	nombreTabla : NombreTabla;
	nombreCol : Nombre;
	calif : Calificador;
	existeCol, patternFound : BOOLEAN;
	inicioBusqueda, posOfPattern: CARDINAL;
	nombres : LstNom;
	StrValor : String;
	valAux : Valor;
	valores : LstVal;
	
BEGIN
	Assign(ObtenerParamComando(1, cmd), nombreTabla);
	(*Assign(ObtenerParamComando(2, cmd), nombreCol);*)
	IF (NOT PerteneceTablaBDatos(nombreTabla, BD)) THEN
		AsignarCodigoError(NOEXISTETABLA,err);
		AsignarStringError(nombreTabla,err);	
	ELSE
		tabla := ObtenerTablaBDatos(nombreTabla,BD);
		patternFound := TRUE;
		inicioBusqueda := 0;
		existeCol := TRUE;
		(****** Armo lista de nombres de columna *****)
		nombres := CrearLstNom();		
		WHILE patternFound AND existeCol DO
			FindNext (':', ObtenerParamComando(2, cmd), inicioBusqueda, patternFound, posOfPattern);
  			(* Looks forward for next occurrence of pattern in stringToSearch, starting the search at
		     	position startIndex. If startIndex < LENGTH(stringToSearch) and pattern is found,
		     	patternFound is returned as TRUE, and posOfPattern contains the start position in
		     	stringToSearch of pattern. Otherwise patternFound is returned as FALSE, and posOfPattern
 		     	is unchanged.*)
			IF patternFound THEN
				Extract(ObtenerParamComando(2, cmd), inicioBusqueda, (posOfPattern-inicioBusqueda),nombreCol);
			ELSE
				Extract(ObtenerParamComando(2, cmd), inicioBusqueda, LENGTH(ObtenerParamComando(2, cmd)),nombreCol);
			END;
			(* Copies at most numberToExtract characters from source to destination, starting at position
    			 startIndex in source.*)
			inicioBusqueda := posOfPattern + 1;
			posOfPattern := 0;
			InsertarNombreLstNom(nombreCol,nombres);
						
		END;
		patternFound := TRUE;
		inicioBusqueda := 1;
		valores := CrearLstVal();
		(****** Armo lista de nombres de valores *****)
		WHILE patternFound DO
			FindNext ("'", ObtenerParamComando(3, cmd), inicioBusqueda, patternFound, posOfPattern);
  			(* Looks forward for next occurrence of pattern in stringToSearch, starting the search at
		     	position startIndex. If startIndex < LENGTH(stringToSearch) and pattern is found,
		     	patternFound is returned as TRUE, and posOfPattern contains the start position in
		     	stringToSearch of pattern. Otherwise patternFound is returned as FALSE, and posOfPattern
 		     	is unchanged.*)
			IF patternFound THEN
				Extract(ObtenerParamComando(3, cmd), inicioBusqueda, (posOfPattern-inicioBusqueda),StrValor);
				inicioBusqueda := posOfPattern + 3;
				posOfPattern := 0;
				IF Equal(StrValor, 'EMPTY') THEN
					valAux := CrearEmptyValor();
				ELSE
					valAux := CrearStringValor(StrValor);
				END;
				InsertarValorLstVal(valAux,valores);
			END;
			
		END;
		insertInto(nombres, valores, tabla, err);
	END;
	IF ((ObtenerCodigoError(err) = NOERROR)) THEN
		WriteString('Tupla insertada con exito en la tabla ');
		WriteString(nombreTabla);
		WriteString('. Existen ');
		WriteCard(ObtenerLargoLstTupla(ObtenerTuplasCnjTupla(ObtenerCnjTuplaTabla(tabla))),1);
		WriteString(' tuplas en la tabla ');
		WriteString(nombreTabla);
		WriteLn();
	ELSE
		PrintError(err);
	END;	
END Insertar;
(***********************************************)
PROCEDURE crearTabla(cmd : Comando);
VAR
	nameTabla : NombreTabla;
	tabla : Tabla;
BEGIN
        Assign(ObtenerParamComando(1,cmd),nameTabla);
	IF PerteneceTablaBDatos(nameTabla, BD) THEN
		AsignarCodigoError(EXISTETABLA,err);
		AsignarStringError(nameTabla,err);
		PrintError(err);
	ELSE	
		tabla := CrearTabla(nameTabla);
		InsertarTablaBDatos(tabla,BD);
		WriteString("Tabla ");
		WriteString(nameTabla);
		WriteString(" creada. Existen ");
		WriteCard(ObtenerCantTablasBDatos(BD),1);
		WriteString(" tablas en la Base de Datos.");
		
	END;	
	WriteLn();
	
END crearTabla;
(***********************************************)
PROCEDURE eliminarTabla(cmd : Comando);
VAR
	nameTabla : NombreTabla;
	tuplasElim : CARDINAL;
	tabla : Tabla;
BEGIN
	Assign(ObtenerParamComando(1,cmd),nameTabla);
	IF (NOT PerteneceTablaBDatos(nameTabla, BD)) THEN
		WriteString("ERROR: La tabla ");
		WriteString(nameTabla);
		WriteString(" no existe.");
	ELSE	
		tuplasElim := ObtenerLargoLstTupla(ObtenerTuplasCnjTupla(ObtenerCnjTuplaTabla(ObtenerTablaBDatos(nameTabla, BD))));
		EliminarTablaBDatos(nameTabla,BD);
		WriteString("Tabla ");
		WriteString(nameTabla);
		WriteString(" eliminada. ");
		WriteCard(tuplasElim, 1);
		WriteString(" tuplas eliminadas. Existen ");
		WriteCard(ObtenerCantTablasBDatos(BD),1);
		WriteString(" tablas en la Base de Datos.");
		
	END;	
	WriteLn();	
END eliminarTabla;
(***********************************************)
PROCEDURE agregarCol(cmd : Comando);
VAR
	tabla : Tabla;
	nombreTabla : NombreTabla;
	nombreCol : NombreColumna;
	calif : Calificador;
BEGIN
	Assign(ObtenerParamComando(1, cmd), nombreTabla);
	Assign(ObtenerParamComando(2, cmd), nombreCol);
	IF (NOT PerteneceTablaBDatos(nombreTabla, BD)) THEN
		WriteString("ERROR: La tabla ");
		WriteString(nombreTabla);
		WriteString(" no existe.");
	ELSE	
		IF (Equal(ObtenerParamComando(3, cmd),'ANY')) THEN
			calif := ANY;
		END;
		IF (Equal(ObtenerParamComando(3, cmd),'NOTEMPTY')) THEN
			calif := NOTEMPTY;
		END;
		IF (Equal(ObtenerParamComando(3, cmd),'PRIMARYKEY')) THEN
			calif := PRIMARYKEY;
		END;
		tabla := ObtenerTablaBDatos(nombreTabla,BD);
		addCol(nombreCol, calif, tabla, err);
		IF ((ObtenerCodigoError(err) = NOERROR)) THEN
			WriteString('Columna ');
			WriteString(nombreCol);
			WriteString(' agregada a tabla ');
			WriteString(nombreTabla);
			WriteString('. Existen ');
			WriteCard(ObtenerCantColEsquema(ObtenerEsquemaTabla(tabla)),1);
			WriteString(' columnas en el esquema de ');
			WriteString(nombreTabla);
			WriteLn();
		ELSE
			PrintError(err);
		END;
	END;	
END agregarCol;
(***********************************************)
PROCEDURE eliminarCol(cmd : Comando);
VAR
	tabla : Tabla;
	nombreTabla : NombreTabla;
	nombreCol : NombreColumna;
	calif : Calificador;
	tuplElim : CARDINAL;
BEGIN
	Assign(ObtenerParamComando(1, cmd), nombreTabla);
	Assign(ObtenerParamComando(2, cmd), nombreCol);
	IF (NOT PerteneceTablaBDatos(nombreTabla, BD)) THEN
		AsignarCodigoError(NOEXISTETABLA,err);
		AsignarStringError(nombreTabla,err);
	ELSE	
		tabla := ObtenerTablaBDatos(nombreTabla,BD);
		dropCol(nombreCol, tabla, tuplElim, err);		
	END;	
	IF ((ObtenerCodigoError(err) = NOERROR)) THEN
		WriteString('Columna ');
		WriteString(nombreCol);
		WriteString(' eliminada de tabla ');
		WriteString(nombreTabla);
		WriteString('. Se eliminaron ');
		WriteCard(tuplElim,1);
		WriteString(' tuplas. Existen ');
		WriteCard(ObtenerCantColEsquema(ObtenerEsquemaTabla(tabla)),1);
		WriteString(' columnas en el esquema de ');
		WriteString(nombreTabla);
		WriteLn();	
	ELSE
		PrintError(err);
	END;	
END eliminarCol;
(***********************************************)
PROCEDURE Eliminar (cmd : Comando);
VAR
	cond : Cond;
	nombreCol : NombreColumna;
	operador : Operador;
	valor : Valor;
	strValor : String;
	tuplElim : CARDINAL;
	nombreTabla : NombreTabla;
	tabla : Tabla;
BEGIN
	tuplElim := 0;
	AsignarCodigoError(NOERROR,err);
	Assign(ObtenerParamComando(1, cmd), nombreTabla);
	IF (NOT PerteneceTablaBDatos(nombreTabla, BD)) THEN
		AsignarCodigoError(NOEXISTETABLA,err);
		AsignarStringError(nombreTabla,err);
	ELSE	
		tabla := ObtenerTablaBDatos(nombreTabla,BD);		
	END;	
	
	IF (ObtenerCantParamComando(cmd) = 2) THEN
		cond := CrearVaciaCond();
	ELSE
		Assign(ObtenerParamComando(2, cmd), nombreCol);
		IF (NOT ExisteCol(nombreCol, tabla)) THEN
		     	AsignarCodigoError(NOEXISTECOLUMNA,err);
			AsignarStringError(nombreCol,err);
		ELSE
		
			Assign(ObtenerParamComando(4, cmd), strValor);
			IF Equal(ObtenerParamComando(3, cmd),'<') THEN
				operador := OPMENOR;	
			ELSE
				IF Equal(ObtenerParamComando(3, cmd),'=') THEN
					operador := OPIGUAL;
				ELSE
					IF Equal(ObtenerParamComando(3, cmd),'>') THEN
						operador := OPMAYOR;
					END;
				END;
			END;
			IF Equal('EMPTY', strValor) THEN
				valor := CrearEmptyValor();
			ELSE
				valor := CrearStringValor(strValor);
			END;
			cond := CrearCond(nombreCol, operador, valor);
			delete(cond, tabla, tuplElim, err);
		END;
	END;
	IF ((ObtenerCodigoError(err) = NOERROR)) THEN
		WriteCard(tuplElim,1);
		WriteString(' tuplas eliminadas en la tabla ');
		WriteString(nombreTabla);
		WriteString('.');
		WriteLn();	
	ELSE
		PrintError(err);
	END;	
END Eliminar;
(***********************************************)
(*************PROGRAMA PRINCIPAL****************)
(***********************************************)
BEGIN
	WriteString("Bienvenidos a P2DBSIM");
	WriteLn();
	WriteString("version 1.0");
	WriteLn();
	WriteString("InCo-FI-UdelaR");
	WriteLn();
	WriteLn();
	WriteString(">");
	
	err := CrearError();	
	cmd := LeerComando();
	cmdName := ObtenerNombreComando(cmd);
	WHILE (NOT Equal(cmdName, "exit") ) DO
		AsignarCodigoError(NOERROR,err);
		IF Equal(cmdName, "createTable") THEN
			crearTabla(cmd);
		END;
		IF Equal(cmdName, "dropTable") THEN
			eliminarTabla(cmd);
		END;
		IF Equal(cmdName, "addCol") THEN
			agregarCol(cmd);
		END;
		IF Equal(cmdName, "dropCol") THEN
			eliminarCol(cmd);
		END;
		IF Equal(cmdName, "printTables") THEN
			ImprimirTablas(cmd);
		END;
		IF Equal(cmdName, "printSchema") THEN
			ImprimirEsquema(cmd);
		END;
		IF Equal(cmdName, "insertInto") THEN
			Insertar(cmd);
		END;
		IF Equal(cmdName, "delete") THEN
			Eliminar(cmd);
		END;
			
		
		WriteString(">");
		cmd := LeerComando();
		cmdName := ObtenerNombreComando(cmd);
	END;
	DestruirBDatos(BD);
	WriteString("chau");

END P2DBSIM.